/*
 * CANopen main program file.
 *
 * This file is a template for other microcontrollers.
 *
 * @file        main_generic.c
 * @author      Janez Paternoster
 * @copyright   2004 - 2020 Janez Paternoster
 *
 * This file is part of CANopenNode, an opensource CANopen Stack.
 * Project home page is <https://github.com/CANopenNode/CANopenNode>.
 * For more information on CANopen see <http://www.can-cia.org/>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "CANopen.h"


#define TMR_TASK_INTERVAL   (1000)          /* Interval of tmrTask thread in microseconds */
#define INCREMENT_1MS(var)  (var++)         /* Increment 1ms variable in tmrTask */

/**
 * User-defined CAN base structure, passed as argument to CO_init.
 */
struct CANbase {
    uintptr_t baseAddress;  /**< Base address of the CAN module */
};

/* Global variables and objects */
    volatile uint16_t   CO_timer1ms = 0U;   /* variable increments each millisecond */


/* main ***********************************************************************/
int main (void){
    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;

    /* Configure microcontroller. */


    /* initialize EEPROM */


    /* increase variable each startup. Variable is stored in EEPROM. */
    OD_powerOnCounter++;


    while(reset != CO_RESET_APP){
/* CANopen communication reset - initialize CANopen objects *******************/
        CO_ReturnError_t err;
        uint16_t timer1msPrevious;

        /* disable CAN and CAN interrupts */
        struct CANbase canBase = {
            .baseAddress = ADDR_CAN1,  /* CAN module address */
        };

        /* initialize CANopen */
        err = CO_init(canBase.baseAddress, 10/* NodeID */, 125 /* bit rate */);
        if(err != CO_ERROR_NO){
            while(1);
            /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
        }


        /* Configure Timer interrupt function for execution every 1 millisecond */


        /* Configure CAN transmit and receive interrupt */


        /* start CAN */
        CO_CANsetNormalMode(CO->CANmodule[0]);

        reset = CO_RESET_NOT;
        timer1msPrevious = CO_timer1ms;

        while(reset == CO_RESET_NOT){
/* loop for normal program execution ******************************************/
            uint16_t timer1msCopy, timer1msDiff;

            timer1msCopy = CO_timer1ms;
            timer1msDiff = timer1msCopy - timer1msPrevious;
            timer1msPrevious = timer1msCopy;


            /* CANopen process */
            reset = CO_process(CO, timer1msDiff, NULL);

            /* Nonblocking application code may go here. */

            /* Process EEPROM */
        }
    }


/* program exit ***************************************************************/
    /* stop threads */


    /* delete objects from memory */
    CO_delete((void*) 0/* CAN module address */);


    /* reset */
    return 0;
}


/* timer thread executes in constant intervals ********************************/
static void tmrTask_thread(void){

    for(;;) {

        /* sleep for interval */

        INCREMENT_1MS(CO_timer1ms);

        if(CO->CANmodule[0]->CANnormal) {
            bool_t syncWas;

            /* Process Sync */
            syncWas = CO_process_SYNC(CO, TMR_TASK_INTERVAL);

            /* Read inputs */
            CO_process_RPDO(CO, syncWas);

            /* Further I/O or nonblocking application code may go here. */

            /* Write outputs */
            CO_process_TPDO(CO, syncWas, TMR_TASK_INTERVAL);

            /* verify timer overflow */
            if(0) {
                CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0U);
            }
        }
    }
}


/* CAN interrupt function *****************************************************/
void /* interrupt */ CO_CAN1InterruptHandler(void){
    CO_CANinterrupt(CO->CANmodule[0]);


    /* clear interrupt flag */
}


/************************* Interrupt Functions *******************************/

/*--------------------------- CAN_IRQ_Handler -------------------------------
 *
 *  CAN interrupt function
 *  If transmit interrupt occured and there are messages in mailbox for
 *  transmit it writes it to hardware and starts the transmission
 *  If receive interrupt occured it reads message from hardware registers
 *  and puts it into receive mailbox
 *---------------------------------------------------------------------------*/

void USB_HP_CAN1_TX_IRQHandler(void)
{
    if (CAN1->TSR & (1 << 0))
    {
        CO_CANinterrupt_Tx(CO->CANmodule[0]);
    }
#if 0
    {
        /* request completed mbx 0 */
        CAN1->TSR |= (1 << 0); /* reset request complete mbx 0 */

        /* If there is a message in the mailbox ready for send, read the
        message from the mailbox and send it                                  */
        if (isr_mbx_receive(CAN_MBX_tx_ctrl[__CAN_CTRL1], (void**)&ptrmsg) != OS_R_OK)
        {
            CAN_hw_wr(__CAN_CTRL1, ptrmsg);
            _free_box(CAN_mpool, ptrmsg);
        }
        else
        {
            isr_sem_send(CAN_wr_sem[__CAN_CTRL1]); /* Return a token back to semaphore */

            CAN1->IER &= ~(1 << 0); /* disable  TME interrupt */
        }
    }
#endif
}
void USB_LP_CAN1_RX0_IRQHandler(void)
{
    if (CAN1->RF0R & 3)
    {
        CO_CANinterrupt_Rx(CO->CANmodule[0]);
    }
#if 0
    {
        /* message pending ? */
        /* If the mailbox isn't full read the message from the hardware and
        send it to the message queue                                          */
        if (isr_mbx_check(CAN_MBX_rx_ctrl[__CAN_CTRL1]) > 0)
        {
            ptrmsg = _alloc_box(CAN_mpool);
            if (ptrmsg)
            {
                CAN_hw_rd(__CAN_CTRL1, 0, ptrmsg); /* Read received message */
                isr_mbx_send(CAN_MBX_rx_ctrl[__CAN_CTRL1], ptrmsg);
            }
        }
        CAN1->RF0R |= (1 << 5); /* Release FIFO 0 output mailbox */
    }
#endif
}

